package com.spontaneappnew.activities;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.RatingBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.spontaneappnew.Categories;
import com.spontaneappnew.Category;
import com.spontaneappnew.NavDrawerActivityConfiguration;
import com.spontaneappnew.NavDrawerItem;
import com.spontaneappnew.NavMenuFBHeader;
import com.spontaneappnew.NavMenuItem;
import com.spontaneappnew.Place;
import com.spontaneappnew.Places;
import com.spontaneappnew.R;
import com.spontaneappnew.adapters.NavDrawerAdapter;

public class AddNewPlaceActivity extends AbstractNavDrawerActivity implements LocationListener {
	
	private boolean isFromImagesCall = false;

	private EditText placeName;
	private EditText placeDesc;
	private RatingBar ratingBar;
	private Spinner categorySpinner;
	
	private TextView mCurrentAddressTextView;
	private Address mCurrentAddress;
	private List<Category> categoriesList;
	public static Uri[] imgsArray;
	// Global variable to hold the current location
    private Location mCurrentLocation;
    // Define an object that holds accuracy, frequency and number of updates parameters
    private LocationRequest mLocationRequest;
    
    private GoogleMap mMap;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		imgsArray = new Uri[6];
		categorySpinner = (Spinner) findViewById(R.id.add_new_place_category_spinner);
		ArrayList<String> spinnerArray = new ArrayList<String>();
		
		categoriesList = Categories.getInstance().getAllCategories();
		for (Category category : categoriesList) {
			spinnerArray.add(category.getName());
		}
		ratingBar = (RatingBar) findViewById(R.id.add_new_place_rating_bar);
		placeName = (EditText) findViewById(R.id.add_new_place_name_edit_text);
		placeDesc = (EditText) findViewById(R.id.add_new_place_description_edit_text);
		
	
		ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, 
				android.R.layout.simple_spinner_dropdown_item, spinnerArray);
		spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		categorySpinner.setAdapter(spinnerArrayAdapter);
        
        mCurrentAddressTextView = (TextView) findViewById(R.id.add_new_place_address_text_view);
        
        mLocationRequest = LocationRequest.create();
        // Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(5000);
        // Set the request for only one updates
        mLocationRequest.setNumUpdates(1);
        
        if(servicesConnected() && isLocationServicesAvailable){
      	  mLocationClient.connect();
        }
        
        mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.add_new_place_map_fragment)).getMap();
	}

	@Override
	protected void onResume() {
		super.onResume();
		if(!mLocationClient.isConnected()){
			// Check if the Google Play Services and location services are available, if not a dialog pops up 
			if(servicesConnected() && isLocationServicesAvailable){
				// check if came from adding an image and then don't show the progress bar because there's no work to be done!
				if(!isFromImagesCall){
					// Show the progress circle so the user knows wer'e working in the background
					showProgressCircle();
				}
				// Connect the client.
		        mLocationClient.connect();
			}
		}
		isFromImagesCall = false;
	}

	@Override
	protected void onPause() {
		// If the client is connected
        if (mLocationClient.isConnected()){
            // Remove location updates for a listener.
            // The current Activity is the listener, so the argument is "this".
        	mLocationClient.removeLocationUpdates(this);
			// Disconnecting the client invalidates it.
	        mLocationClient.disconnect();
        }
		super.onPause();
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.add_new_place, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// user pressed the done button
		if(item.getItemId() == R.id.action_add_new_place_done){
			addNewPlace();
			return true;
		} else if(item.getItemId() == R.id.action_add_new_place_add_images){
			// going to the images activity (camera/gallery) - switch boolean to true so 
			// when we come back onResume will not show progress circle                                
			isFromImagesCall=true;
			Intent intent = new Intent(AddNewPlaceActivity.this, NewPlaceImagesActivity.class);
			startActivity(intent);
			return true;
		}
		else{
			return super.onOptionsItemSelected(item);			
		}
	}

	/*
	 * Provides callbacks that are called when the client is connected or disconnected from the service. 
	 * Most applications implement onConnected(Bundle) to start making requests.
	 * implements GooglePlayServicesClient.ConnectionCallbacks
	 */
	@Override
	public void onConnected(Bundle bundle) {
		mCurrentLocation = mLocationClient.getLastLocation();
		if(mCurrentLocation != null){
			getCurrentAddress();
			changeCameraLocationAndZoom();
		} else{
			Toast.makeText(this, "Getting your current location..", Toast.LENGTH_LONG).show();
		}
		// Make an update request for one accurate current location
		mLocationClient.requestLocationUpdates(mLocationRequest, this);
	}

	@Override
	public void onDisconnected() {}
	
	/**
	    * A subclass of AsyncTask that calls getFromLocation() in the
	    * background. The class definition has these generic types:
	    * Location - A Location object containing
	    * the current location.
	    * Void     - indicates that progress units are not used
	    * String   - An address passed to onPostExecute()
	    */
	    private class GetAddressTask extends AsyncTask<Location, Void, String> {
	        Context mContext;
	        public GetAddressTask(Context context) {
	            super();
	            mContext = context;
	        }
	        
	        /**
	         * Get a Geocoder instance, get the latitude and longitude
	         * look up the address, and return it
	         *
	         * @params params One or more Location objects
	         * @return A string containing the address of the current
	         * location, or an empty string if no address can be found,
	         * or an error message
	         */
	        @Override
	        protected String doInBackground(Location... params) {
	        	// if English works, comment out the next 2 lines and uncomment the 2 after them. if still getting Arabic, leave it in Hebrew
	        	Locale hebrewLocale = new Locale("iw", "IL");
	        	Geocoder geocoder = new Geocoder(mContext, hebrewLocale);
//	        	Locale englishLocale = new Locale("en", "US");
//	        	Geocoder geocoder = new Geocoder(mContext, englishLocale);
	            // Get the current location from the input parameter list
	            Location loc = params[0];
	            // Create a list to contain the result address
	            List<Address> addresses = null;
	            try {
	                //Return 1 address.
	                addresses = geocoder.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);
	            } 
	            catch (IOException e1) {
		            Log.e("LocationAddNewPlaceActivity", "IO Exception in getFromLocation()");
		            e1.printStackTrace();
		            return ("IO Exception trying to get address");
	            } 
	            catch (IllegalArgumentException e2) {
	            	// Error message to post in the log
		            String errorString = "Illegal arguments " +
		                    Double.toString(loc.getLatitude()) +
		                    " , " +
		                    Double.toString(loc.getLongitude()) +
		                    " passed to address service";
		            Log.e("LocationAddNewPlaceActivity", errorString);
		            e2.printStackTrace();
		            return errorString;
	            }
	            // If the reverse geocode returned an address
	            if (addresses != null && addresses.size() > 0) {
	                // Get the first address
	            	mCurrentAddress = addresses.get(0);
	                /*
	                 * Format the first line of address (if available),
	                 * city, and country name.
	                 */
	                String addressText = String.format(
	                        "%s, %s, %s",
	                        // If there's a street address, add it
	                        mCurrentAddress.getMaxAddressLineIndex() > 0 ?
                        		mCurrentAddress.getAddressLine(0) : "",
	                        // Locality is usually a city
                        		mCurrentAddress.getLocality(),
	                        // The country of the address
                        		mCurrentAddress.getCountryName());
	                // Return the text
	                return addressText;
	            } else {
	            	return "No address found";
	            }
	        }
	        
	        /**
	         * A method that's called once doInBackground() completes. Turn
	         * off the indeterminate activity indicator and set
	         * the text of the UI element that shows the address. If the
	         * lookup failed, display the error message.
	         */
	        @Override
	        protected void onPostExecute(String address) {
	            // Hide the progress circle when done working in the background
	        	hideProgressCircle();
		        if(address != null && address != "IO Exception trying to get address" 
		        		&& address != "No address found"){    
	            	// Display the results of the lookup.
		            mCurrentAddressTextView.setText(address);
		            // Update the camera's location and zoom to user's location
		            changeCameraLocationAndZoom();
		        }
		        // Something went wrong, try again
		        else{
		        	getCurrentAddress();
		        }
	        }
	    }
	    
	    private void getCurrentAddress(){
	    	// Ensure that a Geocoder services is available
	        if (Build.VERSION.SDK_INT >=
	                Build.VERSION_CODES.GINGERBREAD
	                            &&
	                Geocoder.isPresent()) {
	            /*
	             * Reverse geocoding is long-running and synchronous.
	             * Run it on a background thread.
	             * Pass the current location to the background task.
	             * When the task finishes,
	             * onPostExecute() displays the address.
	             */
	            (new GetAddressTask(this)).execute(mCurrentLocation);
	        }
	    }

		@Override
		public void onLocationChanged(Location newLocation) {
			mCurrentLocation = newLocation;
	        // take the current location coordinates and get the address to show in the TextView
	        // happens in the background using AsyncTask
	        getCurrentAddress();
		}
		
		// Move camera of the map to user's current location
		private void changeCameraLocationAndZoom(){
			if(mCurrentLocation != null){
				LatLng currLatLng = new LatLng(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
		        MarkerOptions marker = new MarkerOptions().position(currLatLng)
		        		.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
		        // Clear previous marker
		        mMap.clear();
		        mMap.addMarker(marker);
		        // Update the map fragment's camera to the user's location
		        CameraUpdate center = CameraUpdateFactory.newLatLngZoom(currLatLng, 16);
	            
	            mMap.animateCamera(center);
			}
		}
		
		// Called when the V (done button) in the actionbar is called
		// Creates a new Place and adds it to the places list and the server
    	private void addNewPlace() {
        	String name = placeName.getText().toString();
        	String desc = placeDesc.getText().toString();
        	float rating = ratingBar.getRating();
        	Category category = categoriesList.get(categorySpinner.getSelectedItemPosition());
        	String categoryId = category.getID();
        	double lat,lng;
        	// Try to get location, if not loaded yet - show Toast to alert user and return (don't continue with adding the new place)
        	try{
	        	lat = mCurrentLocation.getLatitude();
	        	lng = mCurrentLocation.getLongitude();
        	} catch (Exception e){
        		String msg = "Please wait until we can retrieve your location";
				Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
				return;
        	}
        	// Try to get address, if not loaded yet - show Toast to alert user and return (don't continue with adding the new place)
        	String country = null;
        	String city = null;
        	String street = null;
        	try {
        		country = (String) mCurrentAddress.getCountryName();
            	city = (String) mCurrentAddress.getLocality();
            	street = (String) mCurrentAddress.getAddressLine(0);
			} catch (Exception e) {
				String msg = "Please wait until address loads";
				Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
				return;
			}
        	// If any of the fields are not valid - pop dialog to ask the user to 
        	// fix it and then retry
        	StringBuilder msg = new StringBuilder();
        	if(name == null || name.length() == 0){
        		msg.append("Please fill in the following fields: Name");
        	}
        	if(desc == null || desc.length() == 0){
        		if(msg.length() == 0)
        			msg.append("Please fill in the following fields: Description");
        		else
        			msg.append(", Description");
        	}
        	// At least one of the fields are empty, pop dialog
        	if(msg.length() != 0){
				AlertDialog.Builder builder = new AlertDialog.Builder(AddNewPlaceActivity.this);
				builder.setMessage(msg)
				       .setCancelable(true)
				       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
				           public void onClick(DialogInterface dialog, int id) {
				                dialog.dismiss();
				           }
				       });
				AlertDialog alert = builder.create();
				alert.show();
			}
        	// Name and description are valid, add the new Place to db
        	else{
        		String capitalizedPlaceName = name.substring(0, 1).toUpperCase() + name.substring(1);
        		String userId = getSharedPreferences("PREF", MODE_PRIVATE).getString("FBID", "");
	        	Place newPlace = new Place(capitalizedPlaceName, desc, country, city, street, rating, lat, lng, categoryId, new Date(), userId);
	        	Places.getInstance().addPlace(newPlace,imgsArray);
	        	// change flag to data changed so the view pager adapter of HomeActivity will update
	        	SharedPreferences prefs = getSharedPreferences("PREF", MODE_PRIVATE);
	        	SharedPreferences.Editor editor = prefs.edit();
	        	editor.putBoolean("isRadiusChanged", true);
	        	editor.commit();
	        	finish();
        	}
        }
    	
    	public static Uri[] getImages(){
    		return imgsArray;
    	}
    	
//////////////////////////////// NAV DRAWER ///////////////////////////////////////////////////////////////////////
    	
    	@Override
    	protected void onNavItemSelected(int id) {
    		Intent intent = null;
    		switch ((int)id) {
            // Home nav button was pressed
            case 101:
                intent = new Intent(this, HomeActivity.class);
                break;
            // My places nav drawer was pressed
            case 102:
                intent = new Intent(this, MyPlacesNew.class);
                break;
            // Settings nav button was pressed
            case 103:
            	intent = new Intent(this, SettingsActivity.class);
                break;
            // Logout nav button was pressed
    	    case 108:
    	        callFacebookLogout(this);
    	        break;
    	    }
    		if(intent != null)
            	startActivity(intent);
    	}
    	
    	/*
         * Initialize the nav drawer configurations and returns it to navConf
         */
    	@Override
        protected NavDrawerActivityConfiguration getNavDrawerConfiguration() {
            NavDrawerItem[] menu = new NavDrawerItem[] {
            		NavMenuFBHeader.create( 100, "User"),
                    NavMenuItem.create(101, "Home", "ic_home", this),
                    NavMenuItem.create(102, "My Places", "ic_menu_myplaces", this),
                    NavMenuItem.create(103, "Settings", "ic_menu_settings", this),
                    NavMenuItem.create(105, "About", "ic_action_about_light", this),
                    NavMenuItem.create(107, "Rate Us!", "ic_whats_hot", this),
                    NavMenuItem.create(108, "Logout", "ic_menu_logout", this)};
            
            NavDrawerActivityConfiguration navDrawerActivityConfiguration = new NavDrawerActivityConfiguration();
            navDrawerActivityConfiguration.setMainLayout(R.layout.activity_add_new_place);
            navDrawerActivityConfiguration.setDrawerLayoutId(R.id.drawer_layout);
            navDrawerActivityConfiguration.setLeftDrawerId(R.id.left_drawer);
            navDrawerActivityConfiguration.setNavItems(menu);
            navDrawerActivityConfiguration.setDrawerShadow(R.drawable.drawer_shadow);       
            navDrawerActivityConfiguration.setDrawerOpenDesc(R.string.drawer_open);
            navDrawerActivityConfiguration.setDrawerCloseDesc(R.string.drawer_close);
            navDrawerActivityConfiguration.setBaseAdapter(
                new NavDrawerAdapter(this, R.layout.navdrawer_item, menu ));
            return navDrawerActivityConfiguration;
        }
}
